#pragma once

#include "SimpleLogger.h"
#include "SimpleCriticalSection.h"

namespace RoomFW {

//
// Class:	SimpleLoggerImpl
//
// Description:	Simple logging thread.  Writes to standard output and/or specified file.
//
// Author:	Andrew Sage
//
class SimpleLoggerImpl : public SimpleLogger
{
public:

	//
	// Method:	Instance
	//
	// Description:	Get the single instance of this class.
	//
	// Parameters:	None.
	//
	// Return:	Reference to the single instance of this class.
	//
	static SimpleLoggerImpl& Instance(void);

	//
	// Method:	setConsole
	//
	// Description:	Enable/Disable console output and set buffer size.
	//
	// Parameters:
	//
	//	enable -	Enable flag.
	//
	//	maxLines -	Number of lines in console buffer.
	//
	// Return:	None.
	//
	virtual void setConsole(bool enable, DWORD maxLines = 0);

	//
	// Method:	setFile
	//
	// Description:	Enable/Disable file output and set file name.
	//
	// Parameters:
	//
	//	enable -	Enable flag.
	//
	//	fileName -	Name of log file.
	//
	//	cached -	True to cache logging in memory.  Writes file on close.
	//
	// Return:	None.
	//
	virtual void setFile(bool enable, const char* fileName = 0, size_t maxSize = 0, size_t maxFiles = 0, bool cached = false);

	//
	// Method:	setDebugOutput
	//
	// Description:	Enable/Disable debug output.
	//
	// Parameters:
	//
	//	enable -	Enable flag.
	//
	// Return:	None.
	//
	virtual void setDebugOutput(bool enable);

	//
	// Method:	setVerbosity
	//
	// Description:	Set verbosity(s) to log.  Single LoggingVerbosity value or
	//				multiple LoggingVerbosity values OR'd together.
	//
	// Parameters:
	//
	//	verbosity -	Verbosity(s) to log.
	//
	// Return:	None.
	//
	virtual void setVerbosity(uint32_t verbosity);

	//
	// Method:	log
	//
	// Description:	Log something.  Use the global logger macros above,
	//				rather than calling directly.
	//
	// Parameters:
	//
	//	timestamp -	Current time.
	//
	//	verbosity -	Verbosity.
	//
	//	file -	Source file called from.
	//
	//	line -	Source file line called from.
	//
	//	text -	Actual log message.
	//
	// Return:	None.
	//
	virtual void log(LoggingVerbosity verbosity,
					 const char* file,
					 const int line,
					 const char* text);
	virtual void logV(LoggingVerbosity verbosity,
					 const char* file,
					 const int line,
					 const char* format,
					 ...);

	//
	// Method:	isLv[Verbosity]
	//
	// Description:	Test if a given verbosity is enabled.
	//
	// Parameters:	None.
	//
	// Return:	True if logging that verbosity.
	//
	virtual bool isLvError() const;
	virtual bool isLvWarning() const;
	virtual bool isLvSystem() const;
	virtual bool isLvSoftware() const;
	virtual bool isLvMessage() const;
	virtual bool isLvTrace() const;
	virtual bool isLvSpeed() const;
	virtual bool isLvSpeed2() const;

	// Return the current log file name, if logging to a file, otherwise return an empty std::string.
	virtual std::string getFileName() const;

protected:

	//
	// Thread overrieds.
	//
	virtual bool initializeObject(void);
	virtual bool waitEvent(void);
	virtual bool handleEvent(void);
	virtual void signalStop(void);
	virtual void onStop(void);


private:

	//
	// A log entry.
	//
	struct Entry
	{
	    Entry(const LARGE_INTEGER& _timestamp, std::string _processName, std::string _threadName, LoggingVerbosity _verbosity, const char* _file, int _line, const char* _text)
		:
		timestamp(_timestamp), processName(_processName), threadName(_threadName), verbosity(_verbosity), file(_file), line(_line), text(_text)
		{}

		LARGE_INTEGER timestamp;
		std::string processName;
		std::string threadName;
		LoggingVerbosity verbosity;
		std::string file;
		int line;
		std::string text;
	};
	typedef ::boost::shared_ptr<Entry> EntrySP;

	//
	// Constructor/Destructor.
	//
	SimpleLoggerImpl(void);
	~SimpleLoggerImpl(void);

	//
	// Log everything in the queue.
	//
	void emptyQueue(void);

	//
	// Pop an entry out of the queue.
	//
	EntrySP pop(void);

	//
	// Format a log entry.
	//
	std::string format(EntrySP entry);

	/// Helper function Convert num into an equivalent string.
	std::string itostr(DWORD num);
	

	//
	// Translate verbosity to text.
	//
	static const char* VerbosityText(enum LoggingVerbosity verbosity);

	//
	// Write timestamp to file.
	//
	void timestampFile();

	//
	// Start a new log file.
	//
	void startNewFile();

	//
	// Rename the log file with current date/time appended.  It must be closed first.
	//
	void renameLogFile();

	//
	// Initialize date/time string to append to file name.
	//
	void initFileDateTimeString();

	//
	// Get log file name for renamed log file with index.
	//
	std::string getLogFileName(size_t index);

	//
	// Output to console flag.
	//
	bool console_;

	//
	// Max lines for console window.
	//
	DWORD maxLines_;

	//
	// Output to debug output flag.
	//
	bool debugOutput_;

	//
	// Output to file flag.
	//
	bool file_;

	//
	// Output file name.
	//
	std::string fileName_;

	//
	// Maximum file size.
	//
	size_t maxFileSize_;

	//
	// Current file size.
	//
	size_t curFileSize_;

	//
	// Maximum number of files.
	//
	size_t maxFiles_;

	//
	// Current file index.  First is 0, second 1, etc.  Every time we create a new file:
	// if (maxFiles_ && curFileIndex > maxFiles) delete file index (curFileIndex_ - maxFiles_).
	//
	size_t curFileIndex_;

	//
	// Date time string to append to log file name.
	//
	std::string fileStartTimeString_;

	//
	// Logging verbosity.
	//
	uint32_t verbosity_;

	//
	// Windows performance counter counts per second.
	//
	LARGE_INTEGER frequency_;

	//
	// Windows performance counter counts when logger started.
	// So log times read as fractional seconds since app started.
	//
	LARGE_INTEGER startTime_;

	/// Process name (or ID).  Defined once in this singleton so we don't have to keep querying/formatting it.
	std::string processName_;
	

	//
	// Output streams.  The memory stream could probably be removed.
	//
	std::ostream* outStream_;
	std::ofstream outFileStream_;
	std::ostringstream outMemStream_;

	//
	// Cache flag.  Caching stores all logging in memory until logger is stopped.
	// It isn't very usefull and we don't use it so it should probably be removed.
	//
	bool cached_;

	//
	// Synchronize access to members.
	//
	SimpleCriticalSection allSynch_;

	//
	// Thread stop event.
	//
	SimpleEvent stopEvent_;

	//
	// Log entry queue.
	//
	std::queue<EntrySP> logQueue_;

	//
	// Synchronize queue access.
	//
	SimpleCriticalSection queueSynch_;

	//
	// New log entry event.
	//
	SimpleEvent queueEvent_;

	//
	// Console variables.
	//
	HANDLE stdInHandle_;
	int stdInStream_;
	FILE* stdInFile_;
	HANDLE stdOutHandle_;
	int stdOutStream_;
	FILE* stdOutFile_;
	HANDLE stdErrHandle_;
	int stdErrStream_;
	FILE* stdErrFile_;

	//
	// Verbosity flag events
	//
	SimpleEvent isLvError_;
	SimpleEvent isLvWarning_;
	SimpleEvent isLvSystem_;
	SimpleEvent isLvSoftware_;
	SimpleEvent isLvMessage_;
	SimpleEvent isLvTrace_;
	SimpleEvent isLvSpeed_;
	SimpleEvent isLvSpeed2_;
};

}
